#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#include "../../src/cdslib.h"

#define cast(x) (void *)(x)
#define LENGTH 10

void printChain(_Chain c) 
{
    int i;
    for(i = 0; i < c.length; i++) {
        printf("%d ", (int)_ChainGet(&c, i));
    }
    printf("\n");
}

int main()
{
    int i;
    _Chain c;
    _initChain(&c, _TYPE_CHAIN);

    /* 
     * Testing that getter functions on an empty list produce
     * an error or return NULL
     */
    _ChainGet(&c, 0);
    _ChainSet(&c, 0, cast(12));
    assert(_ChainExtract(&c, 0) == NULL);
    assert(_ChainPopFront(&c) == NULL);
    assert(_ChainPopBack(&c) == NULL);


    for(i = 0; i < LENGTH; i++) {
        _ChainAdd(&c, cast(2*i));
    }
    printChain(c);

    assert(c.length == LENGTH);

    /* Testing return value of _ChainSet */
    assert(_ChainSet(&c, 3, cast(66)) == (void *)6);

    /* Testing set on the 0 index, last index, and in the middle somewhere */
    _ChainSet(&c, 0, cast(12));
    _ChainSet(&c, 9, cast(13));
    _ChainSet(&c, 3, cast(14));
    printChain(c);

    /* Testing bounds checking on set, get, extract, and insert */
    _ChainGet(&c, 1000);
    _ChainSet(&c, 1000, cast(12));
    _ChainExtract(&c, 1000);
    _ChainInsert(&c, 1000, cast(12));
    assert(c.length == LENGTH);

    /* Testing insert on the 0 index, last index, and in the middle somewhere */
    _ChainInsert(&c, 0, cast(11));
    _ChainInsert(&c, c.length, cast(11));
    _ChainInsert(&c, 4, cast(11));
    printChain(c);

    /* Testing popFront and popBack */
    assert(_ChainPopFront(&c) == (void *)11);
    assert(_ChainPopFront(&c) == (void *)12);
    assert(_ChainPopBack(&c) == (void *)11);
    assert(_ChainPopBack(&c) == (void *)13);
    printChain(c);

    /* Testing pushFront and pushBack */
    _ChainPushFront(&c, cast(100));
    _ChainPushBack(&c, cast(200));
    printChain(c);

    /*
     * Testing extract on the 0 index, 
     * last index, and in the middle somewhere
    */
    assert(_ChainExtract(&c, 0) == (void *)100);
    assert(_ChainExtract(&c, c.length - 1) == (void *)200);
    assert(_ChainExtract(&c, 4) == (void *)8);
    printChain(c);

    /* Testing PushBack on an empty Chain */
    while(c.length > 0) {
        _ChainPopFront(&c);
    }
    _ChainPushBack(&c, cast(1));
    printChain(c);

    /* Testing PushFront on an empty Chain */
    _ChainPopBack(&c);
    _ChainPushFront(&c, cast(2));
    printChain(c);

    _deleteChain(&c);

    return EXIT_SUCCESS;
}
